package com.yugao.fintech.antelope.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yugao.fintech.antelope.base.model.constants.TreeCons;
import com.yugao.fintech.antelope.base.model.enums.BoolEnum;
import com.yugao.fintech.antelope.system.assembly.SysDeptAssembly;
import com.yugao.fintech.antelope.system.constants.DeptCons;
import com.yugao.fintech.antelope.system.manager.SysDeptManager;
import com.yugao.fintech.antelope.system.mapper.SysDeptMapper;
import com.yugao.fintech.antelope.system.mapper.SysRoleMapper;
import com.yugao.fintech.antelope.system.mapper.SysUserDeptRelMapper;
import com.yugao.fintech.antelope.system.model.entity.SysDept;
import com.yugao.fintech.antelope.system.model.entity.SysRole;
import com.yugao.fintech.antelope.system.model.entity.SysUserDeptRel;
import com.yugao.fintech.antelope.system.model.rqrs.dept.DeptListReq;
import com.yugao.fintech.antelope.system.model.rqrs.dept.DeptResp;
import com.yugao.fintech.antelope.system.model.rqrs.dept.DeptUpdateReq;
import com.yugao.fintech.antelope.system.model.rqrs.user.UserDeptListReq;
import com.yugao.fintech.antelope.system.service.SysDeptService;
import com.yugao.fintech.framework.assistant.utils.CollectionUtils;
import com.yugao.fintech.framework.assistant.utils.StringUtils;
import com.yugao.fintech.framework.assistant.utils.exception.Assert;
import com.yugao.fintech.framework.assistant.utils.exception.BizException;
import com.yugao.fintech.framework.assistant.utils.tree.TreeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;


@Service
public class SysDeptServiceImpl implements SysDeptService {
    @Autowired
    private SysDeptMapper deptMapper;
    @Autowired
    private SysDeptManager deptManager;
    @Autowired
    private SysUserDeptRelMapper userDeptRelMapper;
    @Autowired
    private SysRoleMapper roleMapper;
    @Autowired
    private SysDeptAssembly sysDeptAssembly;

    @Override
    public List<DeptResp> listDept(DeptListReq req) {
        SysDept sysDept = sysDeptAssembly.toDept(req);
        addIdsToDept(req.getIds(), sysDept);
        sysDept.setStatus(DeptCons.Status.NORMAL);
        List<SysDept> list = deptMapper.selectDeptList(sysDept);
        return list.stream().map(sysDeptAssembly::toDeptTreeResp).collect(Collectors.toList());
    }

    @Override
    public List<DeptResp> listDeptTree(DeptListReq req) {
        SysDept sysDept = sysDeptAssembly.toDept(req);
        addIdsToDept(req.getIds(), sysDept);

        sysDept.setStatus(DeptCons.Status.NORMAL);
        List<SysDept> list = deptMapper.selectDeptList(sysDept);
        List<DeptResp> deptRS = list.stream().map(sysDeptAssembly::toDeptTreeResp).collect(Collectors.toList());
        return this.buildDeptTreeSelect(deptRS);
    }

    private void addIdsToDept(String ids, SysDept out) {
        List<String> idList = StringUtils.toList(ids, ",", String.class);
        if (CollectionUtils.isNotEmpty(idList)) {
            out.getParams().put("ids", idList);
        }
    }

    @Override
    public List<SysDept> listDeptByIds(Collection<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<SysDept> lqw = SysDept.lqw()
                .eq(SysDept::getDelFlag, BoolEnum.FALSE.getCode())
                .in(SysDept::getId, ids)
                .orderByAsc(SysDept::getSortNum);
        return deptMapper.selectList(lqw);
    }

    @Override
    public List<DeptResp> buildDeptTree(List<DeptResp> depts) {
        List<DeptResp> returnList = new ArrayList<>();
        List<Long> tempList = new ArrayList<>();
        for (DeptResp dept : depts) {
            tempList.add(dept.getId());
        }
        for (DeptResp dept : depts) {
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(dept.getParentId())) {
                recursionFn(depts, dept);
                returnList.add(dept);
            }
        }
        if (returnList.isEmpty()) {
            returnList = depts;
        }
        return returnList;
    }

    @Override
    public List<DeptResp> buildDeptTreeSelect(List<DeptResp> depts) {
        return buildDeptTree(depts);
    }

    @Override
    public List<Long> listDeptTreeInRole(Long roleId) {
        SysRole role = roleMapper.selectRoleById(roleId);
        return deptMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly());
    }

    @Override
    public SysDept getDeptById(Long deptId) {
        return deptMapper.selectById(deptId);
    }

    @Override
    public int selectNormalChildrenDeptById(Long deptId) {
        return 0;
    }

    @Override
    public List<Long> listDeptIdByUserId(Long userId) {
        return deptManager.listDeptIdByUserId(userId);
    }

    @Override
    public List<DeptResp> listUserDept(UserDeptListReq req) {
        List<SysDept> list = deptMapper.listUserDept(req);
        return list.stream().map(sysDeptAssembly::toDeptTreeResp).collect(Collectors.toList());
    }

    @Override
    public boolean hasChildByDeptId(Long deptId) {
        return deptManager.hasChildByDeptId(deptId);
    }

    @Override
    public boolean checkDeptExistUser(Long deptId) {
        LambdaQueryWrapper<SysUserDeptRel> lqw = new LambdaQueryWrapper<>();
        lqw.eq(SysUserDeptRel::getDeptId, deptId);
        return userDeptRelMapper.selectList(lqw).size() > 0;
    }


    @Override
    public void checkDeptCodeUnique(String deptCode) {
        LambdaQueryWrapper<SysDept> lqw = new LambdaQueryWrapper<>();
        lqw.eq(SysDept::getDeptCode, deptCode);
        if (deptMapper.selectList(lqw).size() > 0) {
            throw new BizException("部门编码 {} 已存在", deptCode);
        }
    }

    @Override
    public int saveDept(SysDept dept) {
        // 判断是否有父级
        if (Objects.nonNull(dept.getParentId())) {
            SysDept info = deptMapper.selectById(dept.getParentId());
            // 如果父节点不为正常状态,则不允许新增子节点
            if (!DeptCons.Status.NORMAL.equals(info.getStatus())) {
                throw new BizException("部门停用，不允许新增");
            }
            dept.setAncestors(info.getAncestors() + "," + dept.getParentId());
        } else {
            dept.setParentId(TreeCons.ROOT_PARENT_ID);
            dept.setAncestors(TreeCons.ROOT_ANCESTORS_ID);
        }
        return deptMapper.insert(dept);
    }

    @Override
    public boolean updateDept(DeptUpdateReq req) {
        SysDept dept = sysDeptAssembly.toDept(req);

        if (Objects.equals(dept.getParentId(), dept.getId())) {
            throw new BizException("修改部门'" + dept.getDeptName() + "'失败，上级部门不能是自己");
        } else if (StringUtils.equals(DeptCons.Status.DISABLE, dept.getStatus())
                && this.selectNormalChildrenDeptById(dept.getId()) > 0) {
            throw new BizException("该部门包含未停用的子部门！");
        }
        return deptMapper.updateById(dept) > 0;
    }

    @Override
    public void deleteBatch(String[] deptIds) {
        for (String deptIdStr : deptIds) {
            long deptId = Long.parseLong(deptIdStr);
            SysDept sysDept = this.getDeptById(deptId);
            Assert.notNull(sysDept, new BizException("部门不存在"));
            if (BoolEnum.toObject(sysDept.getIsDefault())) {
                throw new BizException("系统默认不能删除");
            }
            if (this.hasChildByDeptId(deptId)) {
                throw new BizException("部门 [ " + sysDept.getDeptName() + " ] 存在下级部门,不允许删除");
            }
            if (this.checkDeptExistUser(deptId)) {
                throw new BizException("部门 [ " + sysDept.getDeptName() + " ] 存在用户,不允许删除");
            }
        }

        LambdaQueryWrapper<SysDept> lqw = new LambdaQueryWrapper<>();
        lqw.in(SysDept::getId, Arrays.asList(deptIds));
        if (deptMapper.delete(lqw) != deptIds.length) {
            throw new BizException("删除失败");
        }
    }

    @Override
    public List<DeptResp> listDeptTreeSync(String parentId, String ids) {
        Consumer<LambdaQueryWrapper<SysDept>> square = i -> {
            i.in(StringUtils.isNotEmpty(ids), SysDept::getId, StringUtils.toList(ids, ",", String.class));
            i.eq(StringUtils.isNotEmpty(parentId), SysDept::getParentId, parentId);
        };

        LambdaQueryWrapper<SysDept> lqw = SysDept.lqw()
                .eq(true, SysDept::getDelFlag, BoolEnum.FALSE.getCode())
                .orderByAsc(SysDept::getSortNum).func(square);
        List<SysDept> list = deptMapper.selectList(lqw);
        List<DeptResp> flatList = list.stream().map(sysDeptAssembly::toDeptTreeResp).collect(Collectors.toList());
        if (StringUtils.isNotEmpty(ids)) {
            return flatList;
        }
        return TreeUtils.build(flatList, StringUtils.isNotEmpty(parentId) ? Long.parseLong(parentId) : TreeCons.ROOT_PARENT_ID);
    }

    /**
     * 递归列表
     */
    private void recursionFn(List<DeptResp> list, DeptResp t) {
        // 得到子节点列表
        List<DeptResp> childList = getChildList(list, t);
        t.setChildren(childList);
        for (DeptResp tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<DeptResp> getChildList(List<DeptResp> list, DeptResp t) {
        List<DeptResp> tlist = new ArrayList<>();
        for (DeptResp n : list) {
            if (StringUtils.isNotNull(n.getParentId()) && Objects.equals(n.getParentId(), t.getId())) {
                tlist.add(n);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<DeptResp> list, DeptResp t) {
        return getChildList(list, t).size() > 0;
    }
}
